#ifndef __TINY_TEST__

#include "vbb_Sensor.h"
#include "vbb_SAVE.h"
#include "vbb_Storage.h"
#include "vbb_FlashMem.h"
#include "fw/vbb_RTC.h"

extern VBB_Storage storage;
extern VBB_RTC rtc;
VBB_Sensor sensor;

unsigned int LastCheckDoorState;
int LastDoorState = -1;

void SwitchStateDoor(bool IsOn)
{
    if (!(IsOn ^ storage.config.ActiveOnHigh_Door))
    {
        if (LastDoorState != 1)
        {
            if (vbb_DebugMode())
                vbb_OUTPUT_Print("DEBUG: DOOR pin is [ON].\r\n");
            
            vbb_FLASHMEM_PushMessageF("$DOOR,%d,%s,%s,%02d%02d%02d,%02d%02d%02d,OPENED",
                VERSION,
                storage.config.OwnerId,
                storage.config.VehicleId,
                /*storage.config.PlateNumber,*/
                rtc.hour,
                rtc.minute,
                rtc.second,
                rtc.day,                
                rtc.month,
                rtc.year % 100);
            LastDoorState = 1;
        }
    }
    else
    {
        if (LastDoorState != 0)
        {
            if (vbb_DebugMode())
                vbb_OUTPUT_Print("DEBUG: DOOR pin is [OFF].\r\n");
            
            vbb_FLASHMEM_PushMessageF("$DOOR,%d,%s,%s,%02d%02d%02d,%02d%02d%02d,CLOSED",
                VERSION,
                storage.config.OwnerId,
                storage.config.VehicleId,
                /*storage.config.PlateNumber,*/
                rtc.hour,
                rtc.minute,
                rtc.second,
                rtc.day,                
                rtc.month,
                rtc.year % 100);
            LastDoorState = 0;
        }
    }
}


unsigned int LastCheckEngineState;
int LastEngineState = -1;

void SwitchStateEngine(bool IsOn)
{
    if (!(IsOn ^ storage.config.ActiveOnHigh_Engine))
    {
        if (LastEngineState != 1)
        {
            if (vbb_DebugMode())
                vbb_OUTPUT_Print("DEBUG: ENGINE pin is [ON].\r\n");
            
            vbb_FLASHMEM_PushMessageF("$ENGINE,%d,%s,%s,%02d%02d%02d,%02d%02d%02d,STARTED",
                VERSION,
                storage.config.OwnerId,
                storage.config.VehicleId,
                /*storage.config.PlateNumber,*/
                rtc.hour,
                rtc.minute,
                rtc.second,
                rtc.day,                
                rtc.month,
                rtc.year % 100);
            LastEngineState = 1;
        }
    }
    else
    {
        if (LastEngineState != 0)
        {
            if (vbb_DebugMode())
                vbb_OUTPUT_Print("DEBUG: ENGINE pin is [OFF].\r\n");
            
            vbb_FLASHMEM_PushMessageF("$ENGINE,%d,%s,%s,%02d%02d%02d,%02d%02d%02d,STOPPED",
                VERSION,
                storage.config.OwnerId,
                storage.config.VehicleId,
                /*storage.config.PlateNumber,*/
                rtc.hour,
                rtc.minute,
                rtc.second,
                rtc.day,                
                rtc.month,
                rtc.year % 100);
            LastEngineState = 0;
        }
    }
}

unsigned int LastCheckACState;
int LastACState = -1;

void SwitchStateAC(bool IsOn)
{
    if (!(IsOn ^ storage.config.ActiveOnHigh_AC))
    {
        if (LastACState != 1)
        {
            if (vbb_DebugMode())
                vbb_OUTPUT_Print("DEBUG: AC pin is [ON].\r\n");
            
            vbb_FLASHMEM_PushMessageF("$AC,%d,%s,%s,%02d%02d%02d,%02d%02d%02d,ON",
                VERSION,
                storage.config.OwnerId,
                storage.config.VehicleId,
                /*storage.config.PlateNumber,*/
                rtc.hour,
                rtc.minute,
                rtc.second,
                rtc.day,                
                rtc.month,
                rtc.year % 100);
            LastACState = 1;
        }
    }
    else
    {                
        if (LastACState != 0)
        {
            if (vbb_DebugMode())
            vbb_OUTPUT_Print("DEBUG: AC pin is [OFF].\r\n");
            
            vbb_FLASHMEM_PushMessageF("$AC,%d,%s,%s,%02d%02d%02d,%02d%02d%02d,OFF",
                VERSION,
                storage.config.OwnerId,
                storage.config.VehicleId,                
                /*storage.config.PlateNumber,*/
                rtc.hour,
                rtc.minute,
                rtc.second,
                rtc.day,                
                rtc.month,
                rtc.year % 100);
            LastACState = 0;
        }
    }
}

void EXTI15_10_IRQHandler(void)
{
    if (EXTI->PR & EXTI_PR_PR14)
    {
        EXTI->PR = EXTI_PR_PR14;
        if (vbb_RTC_GetSec() - LastCheckDoorState >= 1)
        {
            SwitchStateDoor(vbb_PIN_Get(&(sensor.pin_door)));
            LastCheckDoorState = vbb_RTC_GetSec();
        }
    }
}

void EXTI0_IRQHandler(void)
{
    if (EXTI->PR & EXTI_PR_PR0)
    {        
        EXTI->PR = EXTI_PR_PR0;        
        if (vbb_RTC_GetSec() - LastCheckEngineState >= 1)
        {
            SwitchStateEngine(vbb_PIN_Get(&(sensor.pin_engine)));
            LastCheckEngineState = vbb_RTC_GetSec();
        }
    }
}

void EXTI1_IRQHandler(void)
{
    if (EXTI->PR & EXTI_PR_PR1)
    {
        EXTI->PR = EXTI_PR_PR1;        
        if (vbb_RTC_GetSec() - LastCheckACState >= 1)
        {
            SwitchStateAC(vbb_PIN_Get(&(sensor.pin_ac)));
            LastCheckACState = vbb_RTC_GetSec();
        }
    }
}

extern int _utils_pulse_multiply;

void vbb_SENSOR_PulseFire(void)
{
    sensor.CollectedPulse += _utils_pulse_multiply;
    if (vbb_DebugMode())
        vbb_OUTPUT_Print("[!]");
}

void EXTI9_5_IRQHandler(void)
{	
#ifndef __TINY_TEST__
    // ********* BEGIN OF CNS3 ************ 
    if (vbb_DeviceModel() == CNS03) 
    {
        if (EXTI->PR & EXTI_PR_PR7)
        {                        
            EXTI->PR = EXTI_PR_PR7;
            if (vbb_PIN_Get(&(sensor.pin_pulse)))
                vbb_SENSOR_PulseFire();
            
            NVIC_ClearPendingIRQ(EXTI9_5_IRQn);  // Too many pulses
        }
        else if (EXTI->PR & EXTI_PR_PR6)
        {
            EXTI->PR = EXTI_PR_PR6;
            if (vbb_RTC_GetSec() - LastCheckDoorState >= 1)
            {
                LastCheckDoorState = vbb_RTC_GetSec();                
                SwitchStateDoor(vbb_PIN_Get(&(sensor.pin_door)) != 0);
            }
        }
    }
    // *********** END OF CNS3 **************
    else if (vbb_DeviceModel() == CNS01 || vbb_DeviceModel() == BA01)
    {
        if (EXTI->PR & EXTI_PR_PR7)
        {
            EXTI->PR = EXTI_PR_PR7;           
            if (vbb_PIN_Get(&(sensor.pin_pulse)))
            {
                vbb_SENSOR_PulseFire();
            }
            NVIC_ClearPendingIRQ(EXTI9_5_IRQn);  // Too many pulses
        }
    }
#endif	
}

VBB_Pin pin_adc;

void SENSOR_MeasurePowerSupplyInit(void)
{
    vbb_PIN_Init(&pin_adc, GPIOA, 1, PIN_MODE_ANALOG_INPUT);
    
    RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
    
        
    ADC1->CR1 |= ADC_CR1_SCAN;
    ADC1->CR2 |= ADC_CR2_CAL | ADC_CR2_RSTCAL;
    
    vbb_DelayMillis(100);    
    
    ADC1->SQR3 = 0x00000001;
    ADC1->CR2 |= (ADC_CR2_CONT | ADC_CR2_ADON);
    
    vbb_DelayMillis(100);        

    //ADC1->CR2 |= ADC_CR2_ADON;
}

unsigned int SENSOR_MeasurePowerSupply(void)
{       
    ADC1->CR2 |= ADC_CR2_ADON;
    vbb_DelayMillis(100);
    return (ADC1->DR & 0xFFF) * 10;
}

void vbb_SENSOR_Init(void)
{
    SENSOR_MeasurePowerSupplyInit();
    
    // ********* BEGIN OF CNS3 ************ 
    if (vbb_DeviceModel() == CNS03)
    {
        vbb_PIN_Init(&(sensor.pin_pulse), GPIOD, 7, PIN_MODE_FLOATING_INPUT);
        vbb_PIN_Init(&(sensor.pin_ac), GPIOE, 1, PIN_MODE_FLOATING_INPUT);
        vbb_PIN_Init(&(sensor.pin_engine), GPIOB, 7, PIN_MODE_FLOATING_INPUT);
        vbb_PIN_Init(&(sensor.pin_door), GPIOB, 6, PIN_MODE_FLOATING_INPUT);        
        
        // Pulse
        AFIO->EXTICR[1] &= ~AFIO_EXTICR2_EXTI7;
        AFIO->EXTICR[1] |= AFIO_EXTICR2_EXTI7_PD;    
        
        EXTI->RTSR |= EXTI_RTSR_TR7;
        EXTI->FTSR &= ~EXTI_FTSR_TR7;
        
        NVIC_SetPriority(EXTI9_5_IRQn, 9);
        NVIC_EnableIRQ(EXTI9_5_IRQn);
        
        EXTI->IMR |= EXTI_RTSR_TR7;                
        
        // Door
        AFIO->EXTICR[1] &= ~AFIO_EXTICR2_EXTI6;
        AFIO->EXTICR[1] |= AFIO_EXTICR2_EXTI6_PB;
        
        EXTI->RTSR |= EXTI_RTSR_TR6;
        EXTI->FTSR |= EXTI_FTSR_TR6; 

        NVIC_SetPriority(EXTI9_5_IRQn, 9);
        NVIC_EnableIRQ(EXTI9_5_IRQn);
        
        EXTI->IMR |= EXTI_RTSR_TR6;
        EXTI->IMR |= EXTI_FTSR_TR6;        
        
        // AC
        AFIO->EXTICR[0] &= ~AFIO_EXTICR1_EXTI1;
        AFIO->EXTICR[0] |= AFIO_EXTICR1_EXTI1_PE;    
        
        EXTI->RTSR |= EXTI_RTSR_TR1;
        EXTI->FTSR |= EXTI_FTSR_TR1;
        
        NVIC_SetPriority(EXTI1_IRQn, 9);
        NVIC_EnableIRQ(EXTI1_IRQn);
        
        EXTI->IMR |= EXTI_RTSR_TR1; 
        EXTI->IMR |= EXTI_FTSR_TR1;
    }
    // ********* END OF CNS3 ************ 
    else if (vbb_DeviceModel() == CNS01 || vbb_DeviceModel() == BA01)
    {
        vbb_PIN_Init(&(sensor.pin_pulse), GPIOD, 7, PIN_MODE_FLOATING_INPUT);
        vbb_PIN_Init(&(sensor.pin_ac), GPIOD, 1, PIN_MODE_FLOATING_INPUT);
        vbb_PIN_Init(&(sensor.pin_engine), GPIOD, 0, PIN_MODE_FLOATING_INPUT);
        vbb_PIN_Init(&(sensor.pin_door), GPIOA, 14, PIN_MODE_FLOATING_INPUT);        
        
        // Pulse interrupt
        AFIO->EXTICR[1] &= ~AFIO_EXTICR2_EXTI7;
        AFIO->EXTICR[1] |= AFIO_EXTICR2_EXTI7_PD;    
        
        EXTI->RTSR |= EXTI_RTSR_TR7;
        EXTI->FTSR &= ~EXTI_FTSR_TR7;
        
        NVIC_SetPriority(EXTI9_5_IRQn, 9);
        NVIC_EnableIRQ(EXTI9_5_IRQn);
        
        EXTI->IMR |= EXTI_RTSR_TR7;
        
        // Door interrupt
        AFIO->EXTICR[3] &= ~AFIO_EXTICR4_EXTI14;
        AFIO->EXTICR[3] |= AFIO_EXTICR4_EXTI14_PA;
        
        EXTI->RTSR |= EXTI_RTSR_TR14;
        EXTI->FTSR |= EXTI_FTSR_TR14;    
        
        NVIC_SetPriority(EXTI15_10_IRQn, 8);
        NVIC_EnableIRQ(EXTI15_10_IRQn);
        
        EXTI->IMR |= EXTI_RTSR_TR14;
        EXTI->IMR |= EXTI_FTSR_TR14;
        
        // Engine interrupt
        AFIO->EXTICR[0] &= ~AFIO_EXTICR1_EXTI0;
        AFIO->EXTICR[0] |= AFIO_EXTICR1_EXTI0_PD;
        
        EXTI->RTSR |= EXTI_RTSR_TR0;
        EXTI->FTSR |= EXTI_FTSR_TR0;
        
        NVIC_SetPriority(EXTI0_IRQn, 8);
        NVIC_EnableIRQ(EXTI0_IRQn);
        
        EXTI->IMR |= EXTI_RTSR_TR0;
        EXTI->IMR |= EXTI_FTSR_TR0;
        
        // AC interrupt
        AFIO->EXTICR[0] &= ~AFIO_EXTICR1_EXTI1;
        AFIO->EXTICR[0] |= AFIO_EXTICR1_EXTI1_PD;
        
        EXTI->RTSR |= EXTI_RTSR_TR1;
        EXTI->FTSR |= EXTI_FTSR_TR1;
        
        NVIC_SetPriority(EXTI1_IRQn, 8);
        NVIC_EnableIRQ(EXTI1_IRQn);
        
        EXTI->IMR |= EXTI_RTSR_TR1;
        EXTI->IMR |= EXTI_FTSR_TR1;
    }
    
    sensor.CollectedPulse = vbb_BACKUP_GetInt(SAVE_COLLECTED_PULSE);
    
    sensor.LastCollectedPulse = sensor.CollectedPulse;
    sensor.LastProcessTime = 0;
    
    vbb_SENSOR_Update();
}

unsigned int supply_voltage;

void vbb_SENSOR_Update()
{    
    unsigned int dp;        
    
    if (vbb_RTC_GetSec() - sensor.LastProcessTime >= 1)
    {
        supply_voltage = SENSOR_MeasurePowerSupply();
        
        dp = sensor.CollectedPulse - sensor.LastCollectedPulse;
        if (dp > 0)
        {
            sensor.LastVelocity = sensor.Velocity_Int * 100 + sensor.Velocity_Fra;
            
            sensor.Velocity_Int = ((((dp * 10000) / storage.config.PulseOnKm) / (vbb_RTC_GetSec() - sensor.LastProcessTime)) * 3600) / 100;            
            
            sensor.Velocity_Int = (sensor.Velocity_Int + sensor.LastVelocity) / 2; //Filter the velocity by averaging, cleaning noise
            
            sensor.Velocity_Fra = sensor.Velocity_Int % 100;
            sensor.Velocity_Int = sensor.Velocity_Int / 100;    

            if (sensor.Velocity_Int >= storage.config.WarningVelocity)
            {
                //beep 3 times when over speed detected
                /*
                vbb_Buzz(100);
                vbb_Buzz(50);
                vbb_Buzz(50);
                */
                
                /*
                vbb_FLASHMEM_PushMessageF("$OVERSPEED,%d,%s,%s,%02d%02d%02d,%02d%02d%02d,%d.02d",
                    VERSION,
                    storage.config.OwnerId,
                    storage.config.VehicleId,                    
                    rtc.hour,
                    rtc.minute,
                    rtc.second,
                    rtc.day,                
                    rtc.month,
                    rtc.year % 100,                    
                    sensor.Velocity_Int,
                    sensor.Velocity_Fra
                );
                */
            }
        }
        else
        {
            sensor.Velocity_Int = 0;
            sensor.Velocity_Fra = 0;
        }
        
        sensor.LastCollectedPulse = sensor.CollectedPulse;
        sensor.LastProcessTime = vbb_RTC_GetSec();                
    }
    
    sensor.ACPowered = !((vbb_PIN_Get(&(sensor.pin_ac)) ^ storage.config.ActiveOnHigh_AC));
    sensor.DoorClosed = !((vbb_PIN_Get(&(sensor.pin_door)) ^ storage.config.ActiveOnHigh_Door));
    sensor.EngineStarted = !((vbb_PIN_Get(&(sensor.pin_engine)) ^ storage.config.ActiveOnHigh_Engine));
    
    if (vbb_DeviceModel() == CNS03)
        SwitchStateEngine(vbb_PIN_Get(&(sensor.pin_engine)));
    
    vbb_BACKUP_SetInt(SAVE_COLLECTED_PULSE, sensor.CollectedPulse);
}

#endif
